﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Text;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace GraphicalObjects
{
    public class ObjectMesh
    {
        private string filename;

        private Mesh mesh = null;
        private Material[] meshMaterial;
        private Texture[] meshTexture;

        public ObjectMesh(string fileName, ref Device device)
        {
            filename = fileName;

            LoadMesh(ref device);
        }

        public Microsoft.DirectX.Direct3D.Mesh SourceMesh
        {
            get { return mesh; }
        }

        public Microsoft.DirectX.Direct3D.Material[] Materials
        {
            get { return meshMaterial; }
        }

        public Microsoft.DirectX.Direct3D.Texture[] Textures
        {
            get { return meshTexture; }
        }

        internal void LoadMesh(ref Device device)
        {
            //Directory.SetCurrentDirectory("C:\\");
            ExtendedMaterial[] material = null;

            if (filename.Length == 0)
                return;

            mesh = Mesh.FromFile(filename, MeshFlags.SystemMemory, device, out material);

            //------------------------------------------------------------------------------------------------
            // Make sure there are normals which are required for lighting
            if ((mesh.VertexFormat & VertexFormats.Normal) == 0)
            {
                // Clone the mesh
                Mesh tempMesh = null;
                using (mesh)
                {
                    tempMesh = mesh.Clone(mesh.Options.Value, mesh.VertexFormat | VertexFormats.Normal, device);
                    // Compute the normals
                    tempMesh.ComputeNormals();
                }
                mesh = tempMesh;
            }

            // Optimize the mesh for this graphics card's vertex cache so when rendering the mesh's triangle
            // list the vertices will cache hit more often so it won't have to re-execute the vertex shader 
            // on those vertices so it will improve perf.     
            int[] adj = mesh.ConvertPointRepsToAdjacency(null as GraphicsStream);
            mesh.OptimizeInPlace(MeshFlags.OptimizeVertexCache, adj);
            //------------------------------------------------------------------------------------------------

            if (meshTexture == null)
            {
                meshTexture = new Texture[material.Length];
                meshMaterial = new Material[material.Length];

                for (int i = 0; i < material.Length; i++)
                {
                    try
                    {
                        meshMaterial[i] = material[i].Material3D;
                        meshMaterial[i].AmbientColor = meshMaterial[i].DiffuseColor;

                        if (material[i].TextureFilename != null && material[i].TextureFilename.Length > 0)
                        {
                            //Bitmap texture = new Bitmap("..\\Textures\\Ship_06.png");
                            //Bitmap texture = new Bitmap("..\\Textures\\tiger.bmp");
                            Bitmap texture = new Bitmap(material[i].TextureFilename);
                            meshTexture[i] = new Microsoft.DirectX.Direct3D.Texture(device, texture, Usage.None, Pool.Managed);
                        }
                        else
                        {
                            //meshTexture[i] = null;
                        }
                    }
                    catch(Microsoft.DirectX.Direct3D.InvalidDataException e)
                    {
                        throw e;
                    }
                }
            }
        }
    }
}
